

#include "http_protocol_parser.h"
#include "string_util.h"

#include <cstdint>
#include <cstdio>
#include <gtest/gtest.h>
#include <vector>

TEST(HttpProtocolRequest, HeaderLine)
{
    std::string               header_line = "GET /index.html HTTP/1.1\r\n";
    HttpRequestProtocolParser parser;
    int                       length = 0;
    int result = parser.ParseHttpRequestProtocol((const uint8_t *)header_line.c_str(), header_line.size(), length);
    EXPECT_EQ(HttpRequestProtocolParser::NEED_DATA, result);
    auto request = parser.Request();
    printf("method:{%s},uri:{%s},version:{%s}.\n", request->GetMethod().c_str(), request->GetUri().c_str(),
           request->GetVersion().c_str());
    printf("header line size : %ld and use length : %d.\n", header_line.size(), length);
}

TEST(HttpProtocolRequest, HeaderSign)
{
    std::string header_line = "GET /index.html HTTP/1.1\r\n";
    std::string header_sign = "GET /index.html HTTP/1.1\r\nConnection: keep-alive\r\nContent-Type: application/json\r\n";
    int         length      = 0;
    HttpRequestProtocolParser parser;
    int result = parser.ParseHttpRequestProtocol((const uint8_t *)header_sign.c_str(), header_sign.size(), length);
    EXPECT_EQ(HttpRequestProtocolParser::NEED_DATA, result);
    printf("header sign size : %ld and use length : %d.\n", header_sign.size(), length);
    std::string end_sign = "\r\n";

    result               = parser.ParseHttpRequestProtocol((const uint8_t *)end_sign.c_str(), end_sign.size(), length);
    EXPECT_EQ(result, HttpRequestProtocolParser::FINISH);
    printf("header sign size : %ld and use length : %d.\n", header_sign.size() + end_sign.size(), length);
}

TEST(HttpProtocolBody, BodyLength)
{
    std::string header_sign = "GET /index.html HTTP/1.1\r\nConnection: keep-alive\r\nContent-Type: application/json\r\n";
    int         length      = 0;
    HttpRequestProtocolParser parser;
    int result = parser.ParseHttpRequestProtocol((const uint8_t *)header_sign.c_str(), header_sign.size(), length);
    EXPECT_EQ(HttpRequestProtocolParser::NEED_DATA, result);
    std::string content = "Content-Length: 10\r\n\r\n1234567890";
    result              = parser.ParseHttpRequestProtocol((const uint8_t *)content.c_str(), content.size(), length);
    EXPECT_EQ(HttpRequestProtocolParser::FINISH, result);
    auto body = parser.Request()->Body();
    for (auto & c : body)
    {
        printf("%c", c);
    }
    printf(".\n");
}

TEST(HttpProtocolBody, ThreeParser)
{
    std::string header_sign = "GET /index.html HTTP/1.1\r\nConnection: keep-alive\r\nContent-Type: application/json\r\n";
    int         length      = 0;
    HttpRequestProtocolParser parser;
    int result = parser.ParseHttpRequestProtocol((const uint8_t *)header_sign.c_str(), header_sign.size(), length);
    EXPECT_EQ(result, HttpRequestProtocolParser::NEED_DATA);

    std::string content_one = "Content-Length: 12\r\n\r\n123";
    result = parser.ParseHttpRequestProtocol((const uint8_t *)content_one.c_str(), content_one.size(), length);
    EXPECT_EQ(result, HttpRequestProtocolParser::NEED_DATA);
    std::string content_two = "abc";
    result = parser.ParseHttpRequestProtocol((const uint8_t *)content_two.c_str(), content_two.size(), length);
    EXPECT_EQ(result, HttpRequestProtocolParser::NEED_DATA);
    std::string content_three = "456efg";
    result = parser.ParseHttpRequestProtocol((const uint8_t *)content_three.c_str(), content_three.size(), length);
    EXPECT_EQ(result, HttpRequestProtocolParser::FINISH);
    auto body = parser.Request()->Body();
    for (auto & c : body)
    {
        printf("%c", c);
    }
    printf(".\n");
}

TEST(HttpProtocolChunk, ChunkBlock)
{
    std::string header_sign = "GET /index.html HTTP/1.1\r\nConnection: keep-alive\r\nContent-Type: application/json\r\n";
    int         length      = 0;
    HttpRequestProtocolParser parser;
    int result = parser.ParseHttpRequestProtocol((const uint8_t *)header_sign.c_str(), header_sign.size(), length);
    EXPECT_EQ(result, HttpRequestProtocolParser::NEED_DATA);

    std::string content = "Transfer-Encoding: chunked\r\n\r\nc\r\n123456abcdef\r\n6\r\n123456\r\n0\r\n\r\n";
    result              = parser.ParseHttpRequestProtocol((const uint8_t *)content.c_str(), content.size(), length);
    EXPECT_EQ(result, HttpRequestProtocolParser::FINISH);
    auto body = parser.Request()->Body();
    for (auto & c : body)
    {
        printf("%c", c);
    }
    printf(".\n");
}

TEST(HttpProtocolChunk, MultiChunk)
{
    std::string header_sign = "GET /index.html HTTP/1.1\r\nConnection: keep-alive\r\nContent-Type: application/json\r\n";
    int         length      = 0;
    HttpRequestProtocolParser parser;
    int result = parser.ParseHttpRequestProtocol((const uint8_t *)header_sign.c_str(), header_sign.size(), length);
    EXPECT_EQ(result, HttpRequestProtocolParser::NEED_DATA);

    std::string content = "Transfer-Encoding: chunked\r\n\r\nc\r\n123456abcdef\r\n";
    result              = parser.ParseHttpRequestProtocol((const uint8_t *)content.c_str(), content.size(), length);
    EXPECT_EQ(result, HttpRequestProtocolParser::NEED_DATA);

    content = "6\r\n123456\r\n5\r\nqwert\r\n10\r\nabcdef";
    length  = 0;
    result  = parser.ParseHttpRequestProtocol((const uint8_t *)content.c_str(), content.size(), length);
    EXPECT_EQ(result, HttpRequestProtocolParser::NEED_DATA);
    printf("use length : %d.\n", length);
    content = "10\r\nabcdef123456abcd\r\n0\r\n\r\n";
    result  = parser.ParseHttpRequestProtocol((const uint8_t *)content.c_str(), content.size(), length);
    EXPECT_EQ(result, HttpRequestProtocolParser::FINISH);
    auto body = parser.Request()->Body();
    for (auto & c : body)
    {
        printf("%c", c);
    }
    printf(".\n");
}

TEST(BaiduComRequest, Test)
{
    std::string content =
        "474554202f20485454502f312e310d0a486f73743a2062616964752e636f6d0d0a557365722d4167656e743a206375726c2f382e342e302d4445560d0a4163636570743a202a2f2a0d0a0d0a";
    std::vector<uint8_t> data;
    StringUtil::HexStrToCharacter(content, data);
    HttpRequestProtocolParser parser;
    int                       length = 0;
    int                       result = parser.ParseHttpRequestProtocol(data.data(), data.size(), length);
    EXPECT_EQ(result, HttpRequestProtocolParser::FINISH);
    printf("data size : %ld and use length : %d.\n", data.size(), length);
}

TEST(FourNotFound, Test)
{
    std::string content =
        "485454502f312e3120343034204e6f7420466f756e640d0a4163636570742d52616e6765733a2062797465730d0a436f6e74656e742d4c656e6774683a2031300d0a5365727665723a20416b616d61694e657453746f726167650d0a446174653a205765642c2031342041756720323032342031353a34333a303520474d540d0a436f6e6e656374696f6e3a206b6565702d616c6976650d0a0d0a4e6f7420666f756e640a";
    std::vector<uint8_t> data;
    StringUtil::HexStrToCharacter(content, data);
    HttpResponseProtocolParser parser;
    int                        length = 0;
    int                        result = parser.ParseHttpResponseProtocol(data.data(), data.size(), length);
    EXPECT_EQ(result, HttpResponseProtocolParser::FINISH);
    printf("data size : %ld and use length : %d.\n", data.size(), length);
}

int main(int argc, char * argv[])
{
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
